﻿#include "immainwindow.h"
#include <QApplication>
#include <QDomDocument>
#include <QFile>
#include <QLayout>
#include <QMenu>
#include <QProcess>
#include <QStatusBar>
#include <QSystemTrayIcon>
#include <librtc.h>
#include "clientcallback.h"
#include "confsettings.h"
#include "globaltools.h"
#include "litedb.h"
#include "loginwidget.h"
#include "mainwidget.h"
#include "servertimesync.h"
#include "systemsettingform.h"
#include "uitools.h"
#include "usersettings.h"

IMMainWindow::IMMainWindow(QWidget *parent) : MainWindow(1024, 576, parent), basicPixmap(QLatin1Literal(":/gui/tray.png")),basicPixmapGray(convertToGray(basicPixmap))
{
    if (objectName().isEmpty())
        setObjectName(QLatin1String("IMMainWindow"));

    statusBar()->setStyleSheet(QLatin1Literal("QStatusBar{border-bottom: 1px solid gray; border-left: 1px solid gray; border-right: 1px solid gray}"));

    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setContextMenu(new QMenu(this));
    trayIcon->show();
    connect(trayIcon, &QSystemTrayIcon::activated, this, [this](QSystemTrayIcon::ActivationReason reason){
#ifdef Q_OS_LINUX
        if(reason == QSystemTrayIcon::Trigger)
#else
        if(reason == QSystemTrayIcon::DoubleClick)
#endif
        {
            bool activate = true;
            //MainCentralWidget* mainCentral = qobject_cast<MainCentralWidget*>(centralWidget());
            //if(mainCentral)
            //    activate = mainCentral->handleEvent();
            if(isHidden())
            {
                show();
                activate = true;
            }
            if(activate)
            {
                Qt::WindowStates state = windowState();
                if(state.testFlag(Qt::WindowMinimized))
                    setWindowState(state & (~Qt::WindowMinimized));
                activateWindow();
            }
        }
    });
    //TODO:判断trayIcon
    //connect(trayIcon, &QSystemTrayIcon::messageClicked, this, &IMMainWindow::slot_check_update);
    auto client = ClientCallback::instance();
    connect(client, &ClientCallback::signal_user_evnt, this, &IMMainWindow::slot_im_evnt, Qt::QueuedConnection);
    connect(client, &ClientCallback::signal_room_evnt, this, &IMMainWindow::slot_room_evnt, Qt::QueuedConnection);
}

IMMainWindow::~IMMainWindow()
{
    trayIcon->hide();
}

QWidget *IMMainWindow::switchCentral(bool chat)
{
    QSize size;
    QWidget* center = centralWidget();
    if(chat)
    {
        if(center && qobject_cast<MainWidget*>(center))
            return Q_NULLPTR;
        size=defaultSize;
        QString uid = ClientCallback::instance()->get_my_id_QString();
        LiteDb::instance()->init_user_db(uid);
        UserSettings::instance()->resetPersonalSetting(uid);
        center = new MainWidget(this);
        drawTrayIcon(true);
    }
    else
    {
        if(center && qobject_cast<LoginWidget*>(center))
            return Q_NULLPTR;
        size.setWidth(275);
        size.setHeight(485);
        if(MainWidget* central = qobject_cast<MainWidget*>(center))
            central->readyToClose();
        center = new LoginWidget(this);
        drawTrayIcon(false);
        QMenu* menu = trayIcon->contextMenu();
        menu->clear();
        menu->addAction(QObject::trECSUTF8("系统设置"), this, SLOT(slot_system_setting()));
        menu->addAction(QObject::trECSUTF8("退出"), this, SLOT(close()));
        trayIcon->setToolTip(QString());
    }
    statusBar()->setVisible(chat);
    setCentralWidget(center);
    hide();
    layout()->activate();
    if(chat)
    {
        setSize(size);
        showMaximized();
    }
    else
    {
        Qt::WindowStates state = windowState();
        if(state.testFlag(Qt::WindowMinimized) || state.testFlag(Qt::WindowMaximized) || state.testFlag(Qt::WindowFullScreen))
            setWindowState(state & (~Qt::WindowMinimized) & (~Qt::WindowMaximized) & (~Qt::WindowFullScreen));
        setSize(size);
        showNormal();
        activateWindow();
        raise();
    }
    return center;
}

void IMMainWindow::drawTrayIcon(bool online)
{
    if(online)
        trayIcon->setIcon(basicPixmap);
    else
        trayIcon->setIcon(basicPixmapGray);
}

void IMMainWindow::closeCentral()
{
    switchCentral(false);
    ClientCallback::instance()->im_logout();
}

void IMMainWindow::slot_im_evnt(int cmd_type, QVariantHash msg)
{
    if(cmd_type == cmd_type_ack && getParam(msg, cmd_param_ack_cmd).toInt() == cmd_type_heartbeat_req)
    {
        if (qint64 t = getParam(msg, cmd_param_time_len).toLongLong())
            ServerTimeSync::instance()->setTimeLen(t);
        return;
    }
    if(cmd_type == cmd_type_login_im || (cmd_type == cmd_type_ack && getParam(msg, cmd_param_ack_cmd).toInt() == cmd_type_login_im))
    {
        if (qint64 t = getParam(msg, cmd_param_time_len).toLongLong())
            ServerTimeSync::instance()->setTimeLen(t);
        int code = getParam(msg, cmd_param_code).toInt();
        if(LoginWidget* mainLogin = qobject_cast<LoginWidget*>(centralWidget()))
        {
            QString login_id = mainLogin->handle_login_ack(code, msg);
            if(code == error_none)
            {
                if(MainWidget* mainCentral = qobject_cast<MainWidget*>(switchCentral(true)))
                {
                    QMenu* menu = trayIcon->contextMenu();
                    menu->clear();
                    mainCentral->handle_login_ack(msg);
                    //mainCentral->handle_online_list(msg);
                    mainCentral->handle_trayIcon_menu(menu);

                    menu->addAction(QObject::trECSUTF8("系统设置"), this, SLOT(slot_system_setting()));
                    if(!ConfSettings::instance()->updaterName.isEmpty())
                        menu->addAction(QObject::trECSUTF8("检查更新"), this, SLOT(slot_run_updater()));
                    menu->addAction(QObject::trECSUTF8("登出"), this, SLOT(closeCentral()));
                    menu->addAction(QObject::trECSUTF8("退出"),this,SLOT(close()));
                    trayIcon->setToolTip(login_id);
                }
            }
        }
        else if(MainWidget* mainCentral = qobject_cast<MainWidget*>(centralWidget()))
        {
            if(code == error_none)
                mainCentral->handle_login_ack(msg);
            else if(LoginWidget* mainLogin = qobject_cast<LoginWidget*>(switchCentral(false)))
                mainLogin->handle_login_ack(code, msg);
        }
        return;
    }
    if(MainWidget* mainCentral = qobject_cast<MainWidget*>(centralWidget()))
    {
        if(cmd_type == cmd_type_force_out)
        {
            kkim_login_param param = ClientCallback::instance()->get_login_param();
            ClientCallback::instance()->im_logout();
            int reason = getParam(msg, cmd_param_code).toInt();
            if (reason == error_code_blacklist_blocked)
            {
                closeCentral();
                information(QObject::trECSUTF8("提示"), QObject::trECSUTF8("您被系统强迫下线"), this);
                QApplication::quit();
            }
            else if (reason == error_code_login_confilict)
            {
                if(LoginWidget* mainLogin = qobject_cast<LoginWidget*>(switchCentral(false)))
                {
                    if (question(QObject::trECSUTF8("提示"), QObject::trECSUTF8("由于您的帐号在其他机器登陆，您被迫下线\n是否重新登陆?"), this))
                    {
                        mainLogin->handle_login(param.account, param.hashed_password);
                    }
                }
            }
            else if(LoginWidget* mainLogin = qobject_cast<LoginWidget*>(switchCentral(false)))
                mainLogin->handle_login_ack(reason, msg);
        }
        else
            mainCentral->handle_im_event(cmd_type, msg);
    }
}

void IMMainWindow::slot_room_evnt(QVariantHash msg)
{
    if(MainWidget* mainCentral = qobject_cast<MainWidget*>(centralWidget()))
    {
        mainCentral->handle_channel_event(getParam(msg, cmd_param_cmd_type).toInt(), msg);
    }
}

void IMMainWindow::slot_run_updater()
{
    if(ConfSettings::instance()->updaterName.isEmpty())
        return;
    //启动自动更新
    QStringList params(QLatin1Literal("--updater"));
    qint64 myid = ClientCallback::instance()->get_my_id();
    if(myid)
        params<<("UrlQueryString=uid=")+QString::number(myid);
    QString path = QApplication::applicationDirPath()+'/'+ConfSettings::instance()->updaterName+QLatin1Literal(".exe");
    if(!QFile::exists(path))
    {
        information(QObject::trECSUTF8("升级程序不存在"), QObject::trECSUTF8("请检查是否被杀毒程序等误删\n若无法找回请重新安装"));
        return;
    }
    if(QProcess::startDetached(path,params))
    {
        auto settings = UserSettings::instance();
        if(settings->setValueIfChanged(UserSettings::sys_check_update_last, QDate::currentDate()))
            settings->save_system_setting();
    }
}

void IMMainWindow::slot_system_setting()
{
    auto form = SystemSettingForm::showWindow();
    connect(form, &SystemSettingForm::proxyChanged, this, &IMMainWindow::closeCentral, Qt::UniqueConnection);
}

void IMMainWindow::closeEvent(QCloseEvent *e)
{
    MainWindow::closeEvent(e);
    QCoreApplication::quit();
}

void IMMainWindow::setMaximizeButton(bool isMax)
{
    if(MainWidget* central = qobject_cast<MainWidget*>(centralWidget()))
        return central->setMaximizeButton(isMax);
}

bool IMMainWindow::isTitle(const QPoint &pos) const
{
    if(MainWidget* central = qobject_cast<MainWidget*>(centralWidget()))
    {
        return central->isTitle(central->mapFrom(this, pos));
    }
    return false;
}

void IMMainWindow::handleWindowMinimized()
{
}

void IMMainWindow::autoCheckUpdates()
{
    if(ConfSettings::instance()->updaterName.isEmpty())
        return;
    auto settings = UserSettings::instance();
    QDate date = settings->getValue(UserSettings::sys_check_update_last).toDate();
    QDate curDate = QDate::currentDate();
    if(date==curDate)
        return; //今天已经检查过
    QStringList params(QLatin1Literal("--checkupdates"));
    QString path = QApplication::applicationDirPath()+'/'+ConfSettings::instance()->updaterName+QLatin1Literal(".exe");
    if(!QFile::exists(path))
        return;
    QProcess* process = new QProcess;
    QObject::connect(process, &QProcess::stateChanged, this, [process,curDate,this](QProcess::ProcessState newState){
        if(newState == QProcess::NotRunning)
        {
            if(process->error() != QProcess::FailedToStart && process->exitStatus() == QProcess::NormalExit)
            {
                QByteArray read = process->readLine();
                while(!process->atEnd())
                {
                    if(read.startsWith(("<updates")))
                    {
                        read += process->readAll();
                        QDomDocument doc;
                        if(doc.setContent(read, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR))
                        {
                            QDomElement root = doc.documentElement();
                            if(root.hasChildNodes())
                                trayIcon->showMessage(QApplication::applicationDisplayName()+QObject::trECSUTF8("检测到新版本"), QObject::trECSUTF8("请及时检查更新"), QSystemTrayIcon::NoIcon);
                        }
                        break;
                    }
                    else
                        read = process->readLine();
                }
            }
            process->deleteLater();
        }
        else if(newState == QProcess::Running)
        {
            auto settings = UserSettings::instance();
            if(settings->setValueIfChanged(UserSettings::sys_check_update_last,curDate))
                settings->save_system_setting();
        }
    });
    process->start(path, params);
}
